home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Pascal / Applications / NIH Image 1.59 / 1.59 Source / PlugIns.p < prev    next >
Encoding:
Text File  |  1995-06-07  |  27.7 KB  |  933 lines  |  [TEXT/PJMM]

  1. unit PlugIns;
  2. {This unit for utilizing Adobe Photoshop compatible acquisition, export and filter plug-ins}
  3. {is based on code written by Greg Brown, Steven Gonzalo and Richard Ohlendorf.}
  4. {Ohlendorf Research, Inc.}
  5. {818 LaSalle Street}
  6. {Ottawa, IL 61350}
  7. {815-434-5622}
  8. {Applelink--Abraham@AppleLink.com}
  9.  
  10. interface
  11.     uses
  12.         Memory, QuickDraw, Packages, Menus, Events, Fonts, Scrap, ToolUtils, Resources, Errors, Palettes, QDOffscreen, StandardFile, MixedMode,
  13.         Globals, utilities, Graphics, Lut, Filters, Stacks, File1, File2
  14.         {$ifc PowerPC}
  15.         , glue
  16.         {$endc}
  17.         ;
  18.  
  19.     procedure RunAcqPlugIn (item: integer);
  20.     procedure LoadAcqPlugIn (FileName: str255);
  21.     procedure RunExportPlugIn (item: integer);
  22.     procedure LoadExportPlugIn (FileName: str255);
  23.     procedure RunFilterPlugIn (item: integer);
  24.     procedure LoadFilterPlugIn (FileName: str255);
  25.  
  26.  
  27. implementation
  28.  
  29.     const
  30.         uppCallCodeInfo = $00003F80; { PROCEDURE (2 byte param, 4 byte param, 4 byte param, 4 byte param); }
  31.         uppTestAbortProcInfo = $00000011; { FUNCTION : 1 byte result; }
  32.         uppUpdateProgressProcInfo = $000003C0; { PROCEDURE (4 byte param, 4 byte param); }
  33.         
  34.     type
  35.         PluginCodeType=procedure(selector: integer; AcqRec: ptr; var data: LongInt; var result: Integer);
  36.  
  37.         MonitorRec = record
  38.                 gamma: Fixed;
  39.                 redX: Fixed;
  40.                 redY: Fixed;
  41.                 greenX: Fixed;
  42.                 greenY: Fixed;
  43.                 blueX: Fixed;
  44.                 blueY: Fixed;
  45.                 whiteX: Fixed;
  46.                 whiteY: Fixed;
  47.                 ambient: Fixed;
  48.             end;
  49.  
  50.         PlaneMapType = array[0..15] of integer;
  51.  
  52.         AcquireRecord = record
  53.                 serialNumber: LongInt;
  54.                 abortProc: ProcPtr;
  55.                 progressProc: ProcPtr;
  56.                 maxData: LongInt;
  57.                 imageMode: integer;
  58.                 fImageSize: Point;
  59.                 depth: integer;
  60.                 planes: integer;
  61.                 imageHRes: Fixed;
  62.                 imageVRes: Fixed;
  63.                 rLUT: packed array[0..255] of char;
  64.                 gLUT: packed array[0..255] of char;
  65.                 bLUT: packed array[0..255] of char;
  66.                 data: Ptr;
  67.                 theRect: Rect;
  68.                 loPlane: integer;
  69.                 hiPlane: integer;
  70.                 colBytes: integer;
  71.                 rowBytes: LongInt;
  72.                 planeBytes: LongInt;
  73.                 FileName: Str255;
  74.                 vRefNum: integer;
  75.                 dirty: boolean;
  76.          {Version 4 fields}
  77.                 hostSig: OSType;
  78.                 hostProc: ProcPtr;
  79.                 hostModes: LongInt;
  80.                 planeMap: PlaneMapType;
  81.                 canTranspose: boolean;
  82.                 needTranspose: boolean;
  83.                 duotoneInfo: Handle;
  84.                 diskSpace: LongInt;
  85.                 spaceProc: ProcPtr;
  86.                 monitor: MonitorRec;
  87.                 reserved: packed array[0..255] of char;
  88.             end;
  89.  
  90.         FilterColor = packed array[0..3] of char;
  91.  
  92.         FilterRecord = record
  93.                 serialNumber: LongInt;
  94.                 abortProc: ProcPtr;
  95.                 progressProc: ProcPtr;
  96.                 parameters: Handle;
  97.                 fImageSize: Point;
  98.                 planes: integer;
  99.                 filterRect: Rect;
  100.                 background: RGBColor;
  101.                 foreground: RGBColor;
  102.                 maxSpace: LongInt;
  103.                 bufferSpace: LongInt;
  104.                 inRect: Rect;
  105.                 inLoPlane: integer;
  106.                 inHiPlane: integer;
  107.                 outRect: Rect;
  108.                 outLoPlane: integer;
  109.                 outHiPlane: integer;
  110.                 inData: Ptr;
  111.                 inRowBytes: LongInt;
  112.                 outData: Ptr;
  113.                 outRowBytes: LongInt;
  114.                 isFloating: boolean;
  115.                 haveMask: boolean;
  116.                 autoMask: boolean;
  117.                 maskRect: Rect;
  118.                 maskData: Ptr;
  119.                 maskRowBytes: LongInt;
  120.          {Version 4 fields}
  121.                 backColor: FilterColor;
  122.                 foreColor: FilterColor;
  123.                 hostSig: OSType;
  124.                 hostProc: ProcPtr;
  125.                 imageMode: integer;
  126.                 imageHRes: Fixed;
  127.                 imageVRes: Fixed;
  128.                 floatCoord: Point;
  129.                 wholeSize: Point;
  130.                 monitor: MonitorRec;
  131.                 reserved: packed array[0..255] of char;
  132.             end;
  133.  
  134.  
  135.         ExportRecord = record
  136.                 serialNumber: LongInt;
  137.                 abortProc: ProcPtr;
  138.                 progressProc: ProcPtr;
  139.                 maxData: LongInt;
  140.                 imageMode: integer;
  141.                 eImageSize: Point;
  142.                 depth: integer;
  143.                 planes: integer;
  144.                 imageHRes: Fixed;
  145.                 imageVRes: Fixed;
  146.                 rLUT: packed array[0..255] of char;
  147.                 gLUT: packed array[0..255] of char;
  148.                 bLUT: packed array[0..255] of char;
  149.                 theRect: Rect;
  150.                 loPlane: integer;
  151.                 hiPlane: integer;
  152.                 data: Ptr;
  153.                 rowBytes: LongInt;
  154.                 filename: Str255;
  155.                 vRefNum: integer;
  156.                 dirty: BOOLEAN;
  157.                 selectBBox: Rect;
  158.         {Version 4 fields }
  159.                 hostSig: OSType;
  160.                 hostProc: ProcPtr;
  161.                 duotoneInfo: Handle;
  162.                 thePlane: integer;
  163.                 monitor: MonitorRec;
  164.                 reserved: packed array[0..255] of char;
  165.             end;
  166.  
  167.  
  168.     var
  169.         acqData, exportData, filterData, nlines, rowpix: LongInt;
  170.         disppict, srcpict: ptr;
  171.         refnum: integer;
  172.         ShowProgress: boolean;
  173.         ProgressMsg: string[17];
  174.         FilterRec: FilterRecord;
  175.         PluginCode:PluginCodeType;
  176.  
  177.  
  178.     procedure DummyProc;
  179.     begin
  180.     end;
  181.  
  182.     function TestAbort: boolean;
  183.     begin
  184.         if commandperiod then
  185.             testabort := true
  186.         else
  187.             testabort := false;
  188.     end;
  189.  
  190.  
  191.     procedure UpdateProgress (done, total: LongInt);
  192.         var
  193.             whatpercent: integer;
  194.     begin
  195.         if ShowProgress and (done > 0) and (total > 0) and (total >= done) then begin
  196.                 whatpercent := round((done / total) * 100);
  197.                 UpdateMeter(whatpercent, ProgressMsg);
  198.             end;
  199.     end;
  200.  
  201.  
  202.  
  203.     procedure CopyData (src: ptr; theRect: rect; srcRowBytes, dstRowBytes: LongInt; lines: integer);
  204.         var
  205.             i: integer;
  206.             dst: ptr;
  207.             width: LongInt;
  208.     begin
  209.         with theRect do
  210.             width := right - left;
  211.         with info^ do
  212.             dst := ptr(ord4(PicBaseAddr) + therect.top * BytesPerRow + therect.left);
  213.         for i := 0 to lines - 1 do begin
  214.                 BlockMove(src, dst, width);
  215.                 src := ptr(ord4(src) + srcRowBytes);
  216.                 dst := ptr(ord4(dst) + dstRowBytes);
  217.             end;
  218.     end;
  219.  
  220.  
  221.     procedure CopyInterleavedRGBData (src: ptr; theRect: rect; srcRowBytes, dstRowBytes, colBytes: LongInt; lines: integer; planeMap: PlaneMapType);
  222.         var
  223.             i, j, slice, plane, width: integer;
  224.             src2, src3, dst2, dst3: ptr;
  225.     begin
  226.         with theRect do
  227.             width := right - left;
  228.         with info^.StackInfo^ do
  229.             for slice := 1 to 3 do begin
  230.                     CurrentSlice := slice;
  231.                     SelectSlice(slice);
  232.                     plane := planeMap[slice - 1];
  233.                     src2 := src;
  234.                     dst2 := ptr(ord4(info^.PicBaseAddr) + therect.top * info^.BytesPerRow + therect.left);
  235.                     for i := 0 to lines - 1 do begin
  236.                             src3 := ptr(ord4(src2) + plane);
  237.                             dst3 := dst2;
  238.                             for j := 0 to width - 1 do begin
  239.                                     dst3^ := src3^;
  240.                                     src3 := ptr(ord4(src3) + colBytes);
  241.                                     dst3 := ptr(ord4(dst3) + 1);
  242.                                 end;
  243.                             src2 := ptr(ord4(src2) + srcRowBytes);
  244.                             dst2 := ptr(ord4(dst2) + dstRowBytes);
  245.                         end; {for i:=1 to nlines-1}
  246.                 end; {for slice:=1 to 3}
  247.     end;
  248.  
  249.  
  250.     procedure CopyPlanarRGBData (src: ptr; theRect: rect; srcRowBytes, dstRowBytes, planeBytes: LongInt; lines, loPlane, hiPlane: integer);
  251.         var
  252.             i, j, slice, plane: integer;
  253.             src2, dst2: ptr;
  254.             width: LongInt;
  255.     begin
  256.         with theRect do
  257.             width := right - left;
  258.         if loPlane = hiPlane then
  259.             planeBytes := 0;
  260.         if (planeBytes < 0) or (planeBytes > srcRowBytes) then
  261.             planeBytes := width;
  262.         with info^.StackInfo^ do
  263.             for plane := loPlane to hiPlane do begin
  264.                     slice := plane + 1;
  265.                     if slice > 3 then
  266.                         slice := 3;
  267.                     CurrentSlice := slice;
  268.                     SelectSlice(slice);
  269.                     src2 := ptr(ord4(src) + planeBytes * plane);
  270.                     dst2 := ptr(ord4(info^.PicBaseAddr) + therect.top * info^.BytesPerRow + therect.left);
  271.                     for i := 0 to lines - 1 do begin
  272.                             BlockMove(src2, dst2, width);
  273.                             src2 := ptr(ord4(src2) + srcRowBytes);
  274.                             dst2 := ptr(ord4(dst2) + dstRowBytes);
  275.                         end;
  276.                 end;
  277.     end;
  278.  
  279.  
  280.     function MakeRGBStack (name: str255; width, height: integer): boolean;
  281.         var
  282.             ignore: integer;
  283.     begin
  284.         MakeRGBStack := false;
  285.         if not NewPicWindow('RGB', width, height) then
  286.             exit(MakeRGBStack);
  287.         if not MakeStackFromWindow then
  288.             exit(MakeRGBStack);
  289.         if not AddSlice(false) then begin
  290.                 info^.changes := false;
  291.                 ignore := CloseAWindow(info^.wptr);
  292.                 exit(MakeRGBStack);
  293.             end;
  294.         if not AddSlice(false) then begin
  295.                 info^.changes := false;
  296.                 ignore := CloseAWindow(info^.wptr);
  297.                 exit(MakeRGBStack);
  298.             end;
  299.         MakeRGBStack := true;
  300.     end;
  301.  
  302.     procedure GetSFCurDir (var vRefNum: integer; var DirID: LongInt);
  303.   {From "Inside Macintosh:Files", page 3-31.}
  304.         type
  305.             IntPtr = ^integer;
  306.             LongIntPtr = ^LongInt;
  307.         const
  308.             SFSaveDisk = $214;
  309.             CurDirStore = $398;
  310.     begin
  311.         vRefNum := -IntPtr(SFSaveDisk)^;
  312.         DirID := LongIntPtr(CurDirStore)^;
  313.     end;
  314.  
  315.     procedure SetSFCurDir (vRefNum: integer; DirID: LongInt);
  316.         type
  317.             IntPtr = ^integer;
  318.             LongIntPtr = ^LongInt;
  319.         const
  320.             SFSaveDisk = $214;
  321.             CurDirStore = $398;
  322.     begin
  323.         IntPtr(SFSaveDisk)^ := -vRefNum;
  324.         LongIntPtr(CurDirStore)^ := dirID;
  325.     end;
  326.  
  327.  
  328.     function isSystem7: boolean;
  329.     begin
  330.         if not System7 then {These routines uses File Manager calls only available under System 7.}
  331.             PutError('System 7 required to use plug-ins.');
  332.         isSystem7 := System7;
  333.     end;
  334.  
  335.  
  336.     procedure LoadCodeResource (FileName: str255; fType: osType; var codePtr: ProcPtr);
  337.         var
  338.             myReply: StandardFileReply;
  339.             myTypes: SFTypeList;
  340.             err: OSErr;
  341.             CodeResource: handle;
  342.             GotSpec: boolean;
  343.             spec: FSSpec;
  344.             SaveVol: integer;
  345.             SaveDir: LongInt;
  346.     begin
  347.         GotSpec := false;
  348.         if FileName <> '' then begin
  349.                 err := FSMakeFSSpec(PluginsVRefNum, PluginsDirID, FileName, spec);
  350.                 GotSpec := err = noerr;
  351.             end;
  352.         if not GotSpec then begin
  353.                 GetSFCurDir(SaveVol, SaveDir);
  354.                 if PluginsVRefNum <> 0 then
  355.                     SetSFCurDir(PluginsVRefNum, PluginsDirID);
  356.                 myTypes[0] := fType;
  357.                 StandardGetFile(nil, 1, @myTypes, myReply);
  358.                 if myReply.sfGood then begin
  359.                         spec := myReply.sfFile;
  360.                         FileName := myReply.sfFile.name;
  361.                         GotSpec := true
  362.                     end;
  363.                 GetSFCurDir(PluginsVRefNum, PluginsDirID);
  364.                 SetSFCurDir(SaveVol, SaveDir);
  365.             end;
  366.         if GotSpec then begin
  367.                 refnum := FSpOpenResFile(spec, fsCurPerm);
  368.                 if (refnum <> -1) then begin
  369.                         if fType = '8BAM' then begin {Acquistion plug-in}
  370.                                 if pos('Raster', FileName) <> 0 then {Can't show progress indicator if RasterOps frame grabber.}
  371.                                     ShowProgress := false;
  372.                                 if FileName <> LastAcqPlugIn then
  373.                                     acqData := 0;
  374.                                 LastAcqPlugIn := FileName;
  375.                             end
  376.                         else if fType = '8BFM' then begin  {Filter plug-in}
  377.                                 if FileName <> LastFilterPlugIn then begin
  378.                                         filterData := 0;
  379.                                         FilterRec.parameters := nil;
  380.                                     end;
  381.                                 LastFilterPlugIn := FileName;
  382.                             end
  383.                         else if fType = '8BEM' then begin  {Export plug-in}
  384.                                 if FileName <> LastExportPlugIn then
  385.                                     exportData := 0;
  386.                                 LastExportPlugIn := FileName;
  387.                             end;
  388.                         UseResFile(refnum);
  389.                         codeResource := GetIndResource(fType, 1);
  390.                         hlock(codeResource);
  391.                         codePtr := ProcPtr(codeResource^);
  392.                     end
  393.                 else
  394.                     PutError(concat('Error opening plug-in. (Code=', Long2Str(ResError), ')'));
  395.             end;
  396.     end;
  397.  
  398.  
  399. {$ifc not PowerPC}
  400. procedure CallCode (selector: integer; AcqRec: ptr; var data: LongInt; var result: Integer; codePtr: ptr);
  401.     inline
  402.         $205F,   {move.l (a7)+,a0}
  403.         $4E90;   {jsr (a0)}
  404. {$endc}
  405. {Otherwise use C glue routine ("Glue.c") that calls CallUniversalProc. We can't
  406.  call it directly because CallUniversalProc uses a variable number of arguments.}
  407.  
  408.  
  409.     procedure LoadAcqPlugIn (FileName: str255);
  410.  
  411.         const
  412.             AcquireAbout = 0;
  413.             AcquireStart = 1;
  414.             AcquireContinue = 2;
  415.             AcquireFinish = 3;
  416.             AcquirePrepare = 4;
  417.  
  418.             BitMapMode = 0;
  419.             GrayScaleMode = 1;
  420.             IndexedColorMode = 2;
  421.             RGBColorMode = 3;
  422.  
  423.         var
  424.             thiserror: qderr;
  425.             codePtr: ProcPtr;
  426.             AcqRec: acquirerecord;
  427.             result, i, selector, width, height, ignore: integer;
  428.             ok, PlugInDigitizer: boolean;
  429.             dst: ptr;
  430.             name: str255;
  431.  
  432.         procedure ShowInfo (str: str255);
  433.         begin
  434.             with AcqRec do
  435.                 if ControlKeyDown then begin
  436.                         str := concat(str, crStr, crStr, 'imageMode=', long2str(imageMode));
  437.                         str := concat(str, crStr, 'width=', long2str(therect.right - therect.left));
  438.                         str := concat(str, crStr, 'height=', long2str(therect.bottom - therect.top));
  439.                         str := concat(str, crStr, 'depth=', long2str(depth));
  440.                         str := concat(str, crStr, 'planes=', long2str(planes));
  441.                         str := concat(str, crStr, 'colBytes=', long2str(colBytes));
  442.                         str := concat(str, crStr, 'rowBytes=', long2str(rowBytes));
  443.                         str := concat(str, crStr, 'planeBytes=', long2str(planeBytes));
  444.                         str := concat(str, crStr, 'planeMap=', long2str(planeMap[0]), ' ', long2str(planeMap[1]), long2str(planeMap[2]), ' ', long2str(planeMap[3]));
  445.                         str := concat(str, crStr, 'loPlane=', long2str(loPlane));
  446.                         str := concat(str, crStr, 'hiPlane=', long2str(hiPlane));
  447.                         ShowMessage(str);
  448.                         wait(30);
  449.                     end;
  450.         end;
  451.  
  452.         procedure CopyLUT;
  453.             var
  454.                 i: integer;
  455.         begin
  456.             with info^ do begin
  457.                     for i := 0 to 255 do
  458.                         with cTable[i], cTable[i].rgb, AcqRec do begin
  459.                                 value := 0;
  460.                                 red := bsl(ord(rLUT[255 - i]), 8);
  461.                                 green := bsl(ord(gLUT[255 - i]), 8);
  462.                                 blue := bsl(ord(bLUT[255 - i]), 8);
  463.                             end;
  464.                     LoadLUT(cTable);
  465.                     SetupPseudocolor;
  466.                     LutMode := ColorLUT;
  467.                     IdentityFunction := false;
  468.                     UpdateMap;
  469.                 end
  470.         end;
  471.  
  472.         procedure abort (error: integer; started: boolean);
  473.             var
  474.                 msg: str255;
  475.         begin
  476.             if started then
  477.                 CallCode(AcquireFinish, @AcqRec, acqData, result, codePtr);
  478.             CloseResFile(RefNum);
  479.             if MeterWindow <> nil then begin
  480.                     DisposeWindow(MeterWindow);
  481.                     MeterWindow := nil;
  482.                 end;
  483.             if error < 0 then begin
  484.                     msg := '';
  485.                     if error = -108 then
  486.                         msg := concat(crStr, crStr, '"', 'Not enough memory', '"');
  487.                     PutError(concat('Plug-in error (result code=', long2str(error), ')', msg));
  488.                 end;
  489.             PicLeft := PicLeftBase;
  490.             PicTop := PicTopBase;
  491.             AbortMacro;
  492.             {exit(LoadAcqPlugIn);} {ppc-bug}
  493.         end;
  494.  
  495.     begin
  496.         if not isSystem7 then
  497.             exit(LoadAcqPlugIn);
  498.         PlugInDigitizer := pos('Plug-in', FileName) <> 0;
  499.         ShowProgress := true;
  500.         codePtr := nil;
  501.         LoadCodeResource(FileName, '8BAM', codePtr);
  502.         if codePtr = nil then
  503.             exit(LoadAcqPlugIn);
  504.         if TestAbortProc=nil then
  505.             TestAbortProc := NewRoutineDescriptor(@TestAbort, uppTestAbortProcInfo, GetCurrentISA);
  506.         if UpdateProgressProc=nil then 
  507.             UpdateProgressProc := NewRoutineDescriptor(@UpdateProgress, uppUpdateProgressProcInfo, GetCurrentISA);
  508.         with AcqRec do begin
  509.                 SerialNumber := 12345;
  510.                 AbortProc := TestAbortProc;
  511.                 ProgressProc := UpdateProgressProc;
  512.                 MaxData := maxBlock div 2;
  513.                 if MaxData < 25000 then begin
  514.                         PutError('Out of memory.');
  515.                         abort(0, false);
  516.                         exit(LoadAcqPlugIn)
  517.                     end;
  518.                 imageHRes := 0;
  519.                 hostSig := 'Imag';
  520.                 hostProc := nil {@DummyProc};
  521.                 hostModes := 14;{=1110, i.e., grayscale, indexed color and RGB}
  522.                 for i := 0 to 15 do begin
  523.                         planemap[i] := i;
  524.                     end;
  525.                 FileName := '';
  526.                 canTranspose := false;
  527.                 needTranspose := false;
  528.                 duoToneInfo := nil;
  529.                 diskSpace := -1;
  530.                 spaceProc := nil;
  531.                 monitor.gamma := 0;
  532.                 for i := 0 to 255 do
  533.                     reserved[i] := chr(0);
  534.             end;
  535.         ProgressMsg := 'Acquiring Image…';
  536.         ShowInfo('Acquire');
  537.         CallCode(AcquirePrepare, @AcqRec, acqData, result, codePtr);
  538.         if (result <> 0) then
  539.             begin abort(result, false); exit(LoadAcqPlugIn) end;
  540.         ShowInfo('start');
  541.         CallCode(AcquireStart, @AcqRec, acqData, result, codePtr);{call main dialog box etc.}
  542.         if (result <> 0) then
  543.             begin abort(result, false); exit(LoadAcqPlugIn) end;
  544.         if AcqRec.depth = 1 then begin
  545.                 PutError('NIH Image does not support acquisition of bitmap (black and white) images.');
  546.                 abort(0, true);
  547.                 exit(LoadAcqPlugIn)
  548.             end;
  549.         ShowInfo('Opening');
  550.         OpeningPlugInWindow := true; {Causes MakeNewWindow to open window offscreen.}
  551.         if AcqRec.ImageMode = RGBColorMode then
  552.             ok := MakeRGBStack('Untitled', AcqRec.fImageSize.h, AcqRec.fImageSize.v)
  553.         else begin
  554.                 if FileName <> '' then
  555.                     name := FileName
  556.                 else
  557.                     name := 'Untitled';
  558.                 ok := NewPicWindow(name, AcqRec.fImageSize.h, AcqRec.fImageSize.v);
  559.             end;
  560.         OpeningPlugInWindow := false;
  561.         if not ok then begin
  562.                 ShowInfo('Aborting');
  563.                 abort(0, true);
  564.                 exit(LoadAcqPlugIn)
  565.             end;
  566.         with info^, AcqRec do
  567.             if ImageMode = GrayScaleMode then begin
  568.                     if LUTMode = ColorLUT then
  569.                         ResetGrayMap
  570.                 end
  571.             else if ImageMode = RGBColorMode then
  572.                 ResetGrayMap
  573.             else if ImageMode = IndexedColorMode then begin
  574.                     ShowInfo('CopyLUT');
  575.                     CopyLUT;
  576.                 end;
  577.         ShowWatch;
  578.         ShowInfo('Continue');
  579.         repeat
  580.             CallCode(AcquireContinue, @AcqRec, acqData, result, codePtr);
  581.             if result <> 0 then begin
  582.                     info^.changes := false;
  583.                     ignore := CloseAWindow(info^.wptr);
  584.                     abort(result, true);
  585.                     exit(LoadAcqPlugIn)
  586.                 end;
  587.             with AcqRec do
  588.                 if data <> nil then begin
  589.                         width := therect.right - therect.left;
  590.                         height := therect.bottom - therect.top;
  591.                         with Info^ do
  592.                             if ((therect.left + width) <= PixelsPerLine) and (therect.top < nlines) then begin
  593.                                     if (ImageMode = RGBColorMode) and (planes >= 3) and ((hiPlane - loPlane) < 3) then begin
  594.                                             if planeBytes = 1 then
  595.                                                 CopyInterleavedRGBData(data, theRect, rowBytes, Info^.BytesPerRow, colBytes, height, planeMap)
  596.                                             else
  597.                                                 CopyPlanarRGBData(data, theRect, rowBytes, Info^.BytesPerRow, planeBytes, height, loPlane, hiPlane)
  598.                                         end
  599.                                     else
  600.                                         CopyData(data, theRect, rowBytes, Info^.BytesPerRow, height);
  601.                                 end;
  602.                     end;
  603.         until (result <> 0) or (AcqRec.data = nil);
  604.         ShowInfo('Finish');
  605.         CallCode(AcquireFinish, @AcqRec, acqData, result, codePtr);
  606.         CloseResFile(RefNum);
  607.         if MeterWindow <> nil then begin
  608.                 DisposeWindow(MeterWindow);
  609.                 MeterWindow := nil;
  610.             end;
  611.         MoveWindow(info^.wptr, PicLeft, PicTop, true);
  612.         if (AcqRec.imageHRes <> 0) and (not PlugInDigitizer) then
  613.             with info^ do begin
  614.                     xScale := FixRound(AcqRec.imageHRes);
  615.                     yScale := xScale;
  616.                     PixelAspectRatio := 1.0;
  617.                     xUnit := 'inch';
  618.                     SpatiallyCalibrated := true;
  619.                     UpdateTitleBar;
  620.                 end;
  621.         if info^.StackInfo <> nil then
  622.             with info^.StackInfo^ do begin
  623.                     for i := nSlices downto 1 do begin
  624.                             CurrentSlice := i;
  625.                             SelectSlice(CurrentSlice);
  626.                             InvertPic;
  627.                         end;
  628.                     StackType := rgbStack;
  629.                     UpdateTitleBar;
  630.                     ConvertRGBToEightBitColor(true);
  631.                 end
  632.         else
  633.             InvertPic;
  634.         if AcqRec.ImageMode = IndexedColorMode then begin
  635.                 FixColors;
  636.                 WhatToUndo := NothingToUndo;
  637.             end;
  638.         Info^.changes := true;
  639.     end; {LoadAcqPlugIn}
  640.  
  641.  
  642.     procedure PutPlugInMsg (str: str255);
  643.         var
  644.             str2: str255;
  645.     begin
  646.         if System7 then
  647.             PutError(concat(str, ' plug-ins found'))  {Code Warrior bug}
  648.         else
  649.             PutError('System 7 required to use plug-ins.');
  650.     end;
  651.  
  652.  
  653.     procedure RunAcqPlugIn (item: integer);
  654.         var
  655.             name: str255;
  656.     begin
  657.         if nAcqPlugIns = 0 then begin
  658.                 PutPlugInMsg('No acquisition');
  659.                 exit(RunAcqPlugIn);
  660.             end;
  661.         GetMenuItemText(AcquireMenuH, item, name);
  662.         LoadAcqPlugIn(name);
  663.     end;
  664.  
  665.  
  666.     procedure LoadExportPlugIn (FileName: str255);
  667.  
  668.         const
  669.             ExportAbout = 0;
  670.             ExportStart = 1;
  671.             ExportContinue = 2;
  672.             ExportFinish = 3;
  673.             ExportPrepare = 4;
  674.  
  675.             BitMapMode = 0;
  676.             GrayScaleMode = 1;
  677.             IndexedColorMode = 2;
  678.             RGBColorMode = 3;
  679.  
  680.         var
  681.             thiserror: qderr;
  682.             codePtr: ProcPtr;
  683.             ExportRec: ExportRecord;
  684.             result, i, selector, width, height: integer;
  685.             ok: boolean;
  686.             dst: ptr;
  687.             roi, empty: rect;
  688.             offset: LongInt;
  689.  
  690.         procedure ShowInfo (str: str255);
  691.         begin
  692.             with ExportRec do
  693.                 if ControlKeyDown then begin
  694.                         str := concat(str, crStr, crStr, 'imageMode=', long2str(imageMode));
  695.                         str := concat(str, crStr, 'width=', long2str(therect.right - therect.left));
  696.                         str := concat(str, crStr, 'height=', long2str(therect.bottom - therect.top));
  697.                         str := concat(str, crStr, 'depth=', long2str(depth));
  698.                         str := concat(str, crStr, 'planes=', long2str(planes));
  699.                         str := concat(str, crStr, 'rowBytes=', long2str(rowBytes));
  700.                         str := concat(str, crStr, 'loPlane=', long2str(loPlane));
  701.                         str := concat(str, crStr, 'hiPlane=', long2str(hiPlane));
  702.                         ShowMessage(str);
  703.                     end;
  704.         end;
  705.  
  706.         function BadRect: boolean;
  707.         begin
  708.             BadRect := false;
  709.             with info^.PicRect do begin
  710.                     if (ExportRec.theRect.left < left) or (exportRec.theRect.right > right) or (exportRec.theRect.top < top) or (exportRec.theRect.bottom > bottom) then
  711.                         BadRect := true;
  712.                 end;
  713.         end;
  714.  
  715.         procedure abort (result: integer);
  716.         begin
  717.             CloseResFile(RefNum);
  718.             if MeterWindow <> nil then begin
  719.                     DisposeWindow(MeterWindow);
  720.                     MeterWindow := nil;
  721.                 end;
  722.             InvertPic;
  723.             if result < 0 then
  724.                 PutError(concat('Plug-in error (result code=', long2str(result), ').'));
  725.             {exit(LoadExportPlugIn);} {ppc-bug}
  726.         end;
  727.  
  728.     begin
  729.         if not isSystem7 then
  730.             exit(LoadExportPlugIn);
  731.         SetRect(empty, 0, 0, 0, 0);
  732.         with info^ do
  733.             if RoiShowing then
  734.                 roi := RoiRect
  735.             else
  736.                 roi := empty;
  737.         ShowProgress := true;
  738.         codePtr := nil;
  739.         LoadCodeResource(FileName, '8BEM', codePtr);
  740.         if codePtr = nil then
  741.             exit(LoadExportPlugIn);
  742.         if TestAbortProc=nil then
  743.             TestAbortProc := NewRoutineDescriptor(@TestAbort, uppTestAbortProcInfo, GetCurrentISA);
  744.         if UpdateProgressProc=nil then 
  745.             UpdateProgressProc := NewRoutineDescriptor(@UpdateProgress, uppUpdateProgressProcInfo, GetCurrentISA);
  746.         InvertPic;
  747.         with ExportRec, info^ do begin
  748.                 SerialNumber := 12345;
  749.                 AbortProc := TestAbortProc;
  750.                 ProgressProc := UpdateProgressProc;
  751.                 MaxData := maxBlock div 2;
  752.                 if MaxData < 25000 then begin
  753.                         PutError('Out of memory.');
  754.                         abort(0);
  755.                         exit(LoadExportPlugIn);
  756.                     end;
  757.                 if LUTMode = Grayscale then
  758.                     ImageMode := GrayScaleMode
  759.                 else
  760.                     ImageMode := IndexedColorMode;
  761.                 with PicRect, eImageSize do begin
  762.                         h := right - left;
  763.                         v := bottom - top;
  764.                     end;
  765.                 depth := 8;
  766.                 planes := 1;
  767.                 imageHRes := bsl(72, 16);
  768.                 imageVRes := imageHRes;
  769.                 for i := 0 to 255 do
  770.                     with cTable[i].rgb do begin
  771.                             rLUT[255 - i] := chr(bsr(red, 8));
  772.                             gLUT[255 - i] := chr(bsr(green, 8));
  773.                             bLUT[255 - i] := chr(bsr(blue, 8));
  774.                         end;
  775.                 theRect := empty;
  776.                 loPlane := 0;
  777.                 hiPlane := 0;
  778.                 data := PicBaseAddr;
  779.                 rowBytes := BytesPerRow;
  780.                 FileName := title;
  781.                 vRefNum := vRef;
  782.                 dirty := changes;
  783.                 selectBBox := roi;
  784.                 hostSig := 'Imag';
  785.                 hostProc := nil; {@DummyProc}
  786.                 duoToneInfo := nil;
  787.                 thePlane := 0;
  788.                 monitor.gamma := 0;
  789.                 for i := 0 to 255 do
  790.                     reserved[i] := chr(0);
  791.             end;
  792.         ProgressMsg := 'Exporting Image…';
  793.         CallCode(ExportPrepare, @ExportRec, ExportData, result, codePtr);
  794.         if (result <> 0) then begin
  795.             abort(result);
  796.             exit(LoadExportPlugIn);
  797.         end;
  798.         CallCode(ExportStart, @ExportRec, ExportData, result, codePtr);{call main dialog box etc.}
  799.         if (result <> 0) then begin
  800.             abort(result);
  801.             exit(LoadExportPlugIn);
  802.         end;
  803.         ShowWatch;
  804.         repeat
  805.             if BadRect then begin
  806.                 abort(0);
  807.                 exit(LoadExportPlugIn);
  808.             end;
  809.             with ExportRec, info^ do begin
  810.                     offset := theRect.top * BytesPerRow + theRect.left;
  811.                     data := ptr(ord4(PicBaseAddr) + offset);
  812.                 end;
  813.             CallCode(exportContinue, @exportRec, exportData, result, codePtr);
  814.         until (result <> 0) or EmptyRect(exportRec.theRect);
  815.         CallCode(ExportFinish, @ExportRec, ExportData, result, codePtr);
  816.         CloseResFile(RefNum);
  817.         if MeterWindow <> nil then begin
  818.                 DisposeWindow(MeterWindow);
  819.                 MeterWindow := nil;
  820.             end;
  821.         InvertPic;
  822.     end;
  823.  
  824.  
  825.     procedure RunExportPlugIn (item: integer);
  826.         var
  827.             name: str255;
  828.     begin
  829.         if nExportPlugIns = 0 then begin
  830.                 PutPlugInMsg('No export');
  831.                 exit(RunExportPlugIn);
  832.             end;
  833.         GetMenuItemText(ExportMenuH, item, name);
  834.         LoadExportPlugIn(name);
  835.     end;
  836.  
  837.  
  838.     procedure LoadFilterPlugIn (FileName: str255);
  839.  
  840.         const
  841.             filterAbout = 0;
  842.             filterParameters = 1;
  843.             filterPrepare = 2;
  844.             filterStart = 3;
  845.             filterContinue = 4;
  846.             filterFinish = 5;
  847.  
  848.             GrayScaleMode = 1;
  849.  
  850.         var
  851.             thiserror: qderr;
  852.             codePtr: ProcPtr;
  853.             result, i, selector, width, height: integer;
  854.             ok: boolean;
  855.             dst: ptr;
  856.             Empty, roi: rect;
  857.             offset: LongInt;
  858.  
  859.         procedure InvertUndoPic;
  860.             var
  861.                 tPort: GrafPtr;
  862.                 SaveGDevice: GDHandle;
  863.         begin
  864.             SaveGDevice := GetGDevice;
  865.             SetGDevice(osGDevice);
  866.             GetPort(tPort);
  867.             with UndoInfo^ do begin
  868.                     SetPort(GrafPtr(osPort));
  869.                     InvertRect(PicRect);
  870.                 end;
  871.             SetPort(tPort);
  872.             SetGDevice(SaveGDevice);
  873.         end;
  874.  
  875.         procedure abort;
  876.         begin
  877.             CloseResFile(RefNum);
  878.             InvertPic;
  879.             InvertUndoPic;
  880.             if MeterWindow <> nil then begin
  881.                     DisposeWindow(MeterWindow);
  882.                     MeterWindow := nil;
  883.                 end;
  884.             {exit(LoadFilterPlugIn);} {ppc-bug}
  885.         end;
  886.  
  887.         function BadRect: boolean;
  888.         begin
  889.             BadRect := false;
  890.             with info^.PicRect do begin
  891.                     if (FilterRec.inRect.left < left) or (FilterRec.inRect.right > right) or (FilterRec.inRect.top < top) or (FilterRec.inRect.bottom > bottom) then
  892.                         BadRect := true;
  893.                     if (FilterRec.outRect.left < left) or (FilterRec.outRect.right > right) or (FilterRec.outRect.top < top) or (FilterRec.outRect.bottom > bottom) then
  894.                         BadRect := true;
  895.                 end;
  896.         end;
  897.  
  898.     begin {LoadFilterPlugIn}
  899.         if not isSystem7 then
  900.             exit(LoadFilterPlugIn);
  901.         if macro then
  902.             if FileName = 'Reset' then begin
  903.                     FilterRec.parameters := nil;
  904.                     exit(LoadFilterPlugIn);
  905.                 end;
  906.         if NotInBounds or NoUndo or NotRectangular then
  907.             exit(LoadFilterPlugIn);
  908.         with info^ do
  909.             if RoiShowing then
  910.                 roi := RoiRect
  911.             else
  912.                 roi := PicRect;
  913.         KillRoi;
  914.         SetupUndo;
  915.         SetupUndoInfoRec;
  916.         InvertPic;
  917.         InvertUndoPic;
  918.         WhatToUndo := UndoFilter;
  919.         ShowProgress := true;
  920.         codePtr := nil;
  921.         LoadCodeResource(FileName, '8BFM', codePtr);
  922.         if codePtr = nil then
  923.             exit(LoadFilterPlugIn);
  924.         if TestAbortProc=nil then
  925.             TestAbortProc := NewRoutineDescriptor(@TestAbort, uppTestAbortProcInfo, GetCurrentISA);
  926.         if UpdateProgressProc=nil then 
  927.             UpdateProgressProc := NewRoutineDescriptor(@UpdateProgress, uppUpdateProgressProcInfo, GetCurrentISA);
  928.         SetRect(Empty, 0, 0, 0, 0);
  929.         with FilterRec, info^ do begin
  930.                 serialnumber := 12345;
  931.                 AbortProc := TestAbortProc;
  932.                 ProgressProc := UpdateProgressProc;
  933.                 with PicRect, fImageSize do begi